﻿using StockTradTest;
using StockTradTest.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using StockTradTest.strategy;
using Index = StockTradTest.Data.Index;

namespace TestGraphic
{
    public partial class Form5 : Form
    {


        double maxPrice = 0;
        double minPrice = double.MaxValue;
        //股票历史数据
        List<Index> indexData = null;
        List<Indicator> indicators = null;

        const double stockPersent = 0.45f;
        const double bollPersent = 0.23f;
        const double volumePersent = 0.2f;


        Graphics graphics;
        readonly Pen pen;
        readonly Brush brush;
        //鼠标按下时候的位置记录
        Point mouseDownPoint = Point.Empty;
        bool LMouseDown = false;
        //显示的开始位置
        int showStartCount = 0;
        int showCount = 0;
        //记录的
        int oldShowStartCount = 0;
        //最大计数
        int maxCount = 0;
        //绘图用缓存
        Bitmap bmp;
        //窗口处于处理阶段
        public static bool inFocus = true;
        readonly Form2 textForm;

        //线的x坐标
        int lineX = -1;
        //指数列表
        string[] indexCodeList;
        public Form5()
        {
            pen = new Pen(Color.Black, 1);
            brush = new SolidBrush(Color.DarkGray);
            InitializeComponent();
            bmp = new Bitmap(Width, Height);
            graphics = Graphics.FromImage(bmp);

            textForm = new Form2();
            textForm.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form5_MouseMove);
            textForm.m_Label.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form5_MouseMove);
            //textForm.label_Text.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form5_MouseMove);
            textForm.Visible = false;
            InitComboBox();
            comboBox_code.SelectedIndex = 0;
            textBox_variable.Text = "20";
            GraphicsClear();

        }
        void InitComboBox()
        {
            comboBox_code.Items.AddRange(StockTradTest.Data.Index.IndexDic.Values.ToArray());
            indexCodeList = StockTradTest.Data.Index.IndexDic.Keys.ToArray();
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            this.CreateGraphics().DrawImage(bmp, 0, 0);

        }
        private void DrawStock(int startCount = 0)
        {
            maxPrice = 0;
            minPrice = double.MaxValue;
            double heightLength = Height * stockPersent - 5;
            if (indexData == null) return;
            maxCount = indexData.Count;
            showCount = (int)Math.Floor(Width/ 5f) - 5;
            if (startCount + showCount >= maxCount)
            {
                startCount = maxCount - showCount;
                showStartCount = startCount;
            }
            for (int i = startCount; i < startCount + showCount; i++)
            {
                if (maxPrice < indexData[i].HighPrice) maxPrice = indexData[i].HighPrice;
                if (minPrice > indexData[i].LowPrice) minPrice = indexData[i].LowPrice;
            }
            List<Point> points = new List<Point>();
            double length = maxPrice - minPrice;

            for (int i = 0; i < showCount; i++)
            {
                Point point1 = new Point(i * 5 + 4, 5 + (int)(heightLength - (indexData[i + startCount].HighPrice - minPrice) / length * heightLength));
                Point point2 = new Point(i * 5 + 4, 5 + (int)(heightLength - (indexData[i + startCount].LowPrice - minPrice) / length * heightLength));
                Point point3 = new Point(i * 5 + 4, 5 + (int)(heightLength - (indexData[i + startCount].OpenPrice - minPrice) / length * heightLength));
                Point point4 = new Point(i * 5 + 4, 5 + (int)(heightLength - (indexData[i + startCount].ClosePrice - minPrice) / length * heightLength));
                if (indexData[i + startCount].OpenPrice < indexData[i + startCount].ClosePrice)
                {
                    graphics.DrawLine(new Pen(Color.Red, 1), point1, point2);
                    graphics.DrawLine(new Pen(Color.Red, 3), point3, point4);
                }
                else
                {
                    graphics.DrawLine(new Pen(Color.Green, 1), point1, point2);
                    graphics.DrawLine(new Pen(Color.Green, 3), point3, point4);
                }

            }
            if (points.Count == 0) return;
            int count = 0;
            for (int i = 0; i < showCount; i++)
            {
                graphics.DrawLine(pen, points[count++], points[count++]);
            }

        }
        // 在主图上绘制Ma移动平均线
        private void DrawMa(int n, Color color)
        {
            double heightLength = Height * stockPersent - 5;
            if (indicators == null) return;
            List<Point> points = new List<Point>();
            double length = maxPrice - minPrice;
            double tempMa;
            for (int i = 0; i < showCount; i++)
            {
                tempMa = n switch
                {
                    5 => indicators[i + showStartCount].Ma5,
                    10 => indicators[i + showStartCount].Ma10,
                    20 => indicators[i + showStartCount].Ma20,
                    30 => indicators[i + showStartCount].Ma60,
                    60 => indicators[i + showStartCount].Ma60,
                    120 => indicators[i + showStartCount].Ma120,
                    250 => indicators[i + showStartCount].Ma250,
                    _ => 0
                };

                points.Add(new Point(i * 5 + 4, 5 + (int)(heightLength - (tempMa - minPrice) / length * heightLength)));
            }
            if (points.Count > 0) graphics.DrawLines(new Pen(color, 1), points.ToArray());

        }
        /// <summary>
        /// 绘制换手量和成交资金量
        /// </summary>
        private void DrawVolume()
        {
            double heightLength = Height * volumePersent - 5;
            double title = Height * (stockPersent + volumePersent) + 4;
            if (indexData == null || indexData.Count == 0) return;
            double maxHand = 0;
            double maxAmount = 0;
            for (int i = showStartCount; i < showCount + showStartCount; i++)
            {
                if (maxHand < indexData[i].TotalHand) maxHand = indexData[i].TotalHand;
                if (maxAmount < indexData[i].TotalAmount) maxAmount = indexData[i].TotalAmount;
            }
            for (int i = 0; i < showCount; i++)
            {
                Point point1 = new Point(i * 5 + 3, (int)title);
                Point point2 = new Point(i * 5 + 3, (int)(title - indexData[i + showStartCount].TotalHand / maxHand * heightLength));
                Point point3 = new Point(i * 5 + 5, (int)title);
                Point point4 = new Point(i * 5 + 5, (int)(title - indexData[i + showStartCount].TotalAmount / maxAmount * heightLength));
                graphics.DrawLine(new Pen(Color.LightGreen, 2), point3, point4);
                graphics.DrawLine(new Pen(Color.DarkRed, 2), point1, point2);
            }

        }
        private void DrawBoll()
        {
            double heightLength = Height * bollPersent - 5;
            double title = Height * (stockPersent + volumePersent + bollPersent) + 5;

            if (indexData == null || indexData.Count == 0) return;
            double maxPrice = 0;
            double minPrice = double.MaxValue;
            for (int i = showStartCount; i < showCount + showStartCount; i++)
            {
                if (i == maxCount) break;
                if (maxPrice < indicators[i].BollUp) maxPrice = indicators[i].BollUp;
                if (minPrice > indicators[i].BollDown) minPrice = indicators[i].BollDown;
                if (maxPrice < indexData[i].HighPrice) maxPrice = indexData[i].HighPrice;
                if (minPrice > indexData[i].LowPrice) minPrice = indexData[i].LowPrice;
            }
            List<Point> pointsUp = new List<Point>();
            List<Point> pointsMd = new List<Point>();
            List<Point> pointsDown = new List<Point>();
            double length = maxPrice - minPrice;
            for (int i = 0; i < showCount; i++)
            {
                if (i == maxCount) break;
                pointsUp.Add(new Point(i * 5 + 4, (int)(title - (indicators[i + showStartCount].BollUp - minPrice) / length * heightLength)));
                pointsMd.Add(new Point(i * 5 + 4, (int)(title - (indicators[i + showStartCount].BollMd - minPrice) / length * heightLength)));
                pointsDown.Add(new Point(i * 5 + 4, (int)(title - (indicators[i + showStartCount].BollDown - minPrice) / length * heightLength)));
            }
            if (pointsUp.Count > 0)
            {
                graphics.DrawLines(new Pen(Color.White, 1), pointsUp.ToArray());
                graphics.DrawLines(new Pen(Color.Yellow, 1), pointsMd.ToArray());
                graphics.DrawLines(new Pen(Color.Purple, 1), pointsDown.ToArray());
            }
            //Draw Stock on Indicator

            if (indexData == null) return;
            List<Point> points = new List<Point>();

            for (int i = 0; i < showCount; i++)
            {
                if (i == maxCount) break;
                Point point1 = new Point(i * 5 + 4, (int)(title - (indexData[i + showStartCount].HighPrice - minPrice) / length * heightLength));
                Point point2 = new Point(i * 5 + 4, (int)(title - (indexData[i + showStartCount].LowPrice - minPrice) / length * heightLength));
                Point point3 = new Point(i * 5 + 4, (int)(title - (indexData[i + showStartCount].OpenPrice - minPrice) / length * heightLength));
                Point point4 = new Point(i * 5 + 4, (int)(title - (indexData[i + showStartCount].ClosePrice - minPrice) / length * heightLength));
                if (indexData[i].OpenPrice < indexData[i].ClosePrice)
                {
                    graphics.DrawLine(new Pen(Color.Red, 1), point1, point2);
                    graphics.DrawLine(new Pen(Color.Red, 3), point3, point4);
                }
                else
                {
                    graphics.DrawLine(new Pen(Color.Green, 1), point1, point2);
                    graphics.DrawLine(new Pen(Color.Green, 3), point3, point4);
                }

            }
            if (points.Count == 0) return;
            int count = 0;
            for (int i = 0; i < showCount; i++)
            {
                graphics.DrawLine(pen, points[count++], points[count++]);
            }

        }
        private void DrawAll(int startCount)
        {
            DrawStock(startCount);
            DrawMa(20, Color.LightGreen);
            DrawMa(60, Color.Red);
            DrawVolume();
            DrawBoll();
        }
        private void Clear()
        {
            if (Base.CurrentIndexCode != indexCodeList[comboBox_code.SelectedIndex])
            {
                Base.CurrentIndexCode = "";
                indexData = null;
                indicators = null;
                maxCount = 0;
            }
            GraphicsClear();
        }

        private void GraphicsClear()
        {
            graphics.Clear(Color.WhiteSmoke);
            graphics.FillRectangle(brush, new RectangleF(2, 2, Width - 20, (int)(Height * stockPersent)));
            graphics.DrawRectangle(pen, new Rectangle(1, 1, Width - (int)pen.Width - 18, (int)(Height * stockPersent)));
            graphics.FillRectangle(brush, new RectangleF(2, (int)(Height * stockPersent + 5), Width - 20, (int)(Height * volumePersent)));
            graphics.DrawRectangle(pen, new Rectangle(1, (int)(Height * stockPersent + 5), Width - (int)pen.Width - 18, (int)(Height * volumePersent)));
            graphics.FillRectangle(brush, new RectangleF(2, (int)(Height * (stockPersent + volumePersent) + 10), Width - 20, (int)(Height * bollPersent)));
            graphics.DrawRectangle(pen, new Rectangle(1, (int)(Height * (stockPersent + volumePersent) + 10), Width - (int)pen.Width - 18, (int)(Height * bollPersent)));
        }
        private void Form5_MouseDown(object sender, MouseEventArgs e)
        {

            textForm.Visible = false;
            if (e.Button == MouseButtons.Left)
            {
                Cursor = Cursors.Hand;

                if (LMouseDown == false)
                {
                    mouseDownPoint = new Point(-e.X, -e.Y);
                    LMouseDown = true;
                    oldShowStartCount = showStartCount;
                    return;
                }
            }

        }

        private void Form5_MouseUp(object sender, MouseEventArgs e)
        {
            LMouseDown = false;
            Cursor = Cursors.Default;
            oldShowStartCount = showStartCount;
        }

        private void Form5_MouseMove(object sender, MouseEventArgs e)
        {
            if (!inFocus) return;
            if (LMouseDown)
            {
                showStartCount = oldShowStartCount + (-e.X - mouseDownPoint.X) / 5;
                if (showStartCount < 0) showStartCount = 0;
                if (showStartCount != oldShowStartCount)
                {

                    label_Msg.Text = showStartCount.ToString();
                    Clear();

                    DrawAll(showStartCount);
                    this.CreateGraphics().DrawImage(bmp, 0, 0);
                }
            }
            else
            {
                if (indexData == null || indicators == null)
                {
                    return;
                }
                Point p = this.PointToClient(Cursor.Position);
                if (p.X <= Width * 0.8)
                {
                    if (p.Y < Height * 0.5)
                    {
                        textForm.Location = this.PointToScreen(new Point(p.X + 10, p.Y));
                    }
                    else
                    {
                        textForm.Location = this.PointToScreen(new Point(p.X + 10, p.Y - textForm.Height - 10));
                    }
                }
                else
                {
                    if (p.Y < Height * 0.5)
                    {
                        textForm.Location = this.PointToScreen(new Point(p.X - textForm.Width - 10, p.Y));
                    }
                    else
                    {
                        textForm.Location = this.PointToScreen(new Point(p.X - textForm.Width - 10, p.Y - textForm.Height - 10));
                    }
                }
                if (textForm.Visible == false) textForm.Visible = true;
                if (this.ClientSize.Width > p.X & 0 < p.X & this.ClientSize.Height - 30 > p.Y & 0 < p.Y)
                {
                    int x = (int)((MousePosition.X - this.Location.X) / 5) * 5 - 6;
                    if (lineX != x)
                    {
                        lineX = x;
                        GraphicsClear();

                        DrawAll(showStartCount);
                        graphics.DrawLine(new Pen(Color.Black, 1), new Point(x, 1), new Point(x, (int)(Height * 0.89)));

                        this.CreateGraphics().DrawImage(bmp, 0, 0);
                        int dateCount = showStartCount + (x - 4) / 5;
                        if (dateCount < 0 || dateCount >= maxCount) return;
                        Index dayData = indexData[showStartCount + (x - 4) / 5];
                        Indicator dayIndicator = indicators[showStartCount + (x - 4) / 5];
                        string text = string.Format("代码:{0}\n" +
                            "名称:{1}\n" +
                            "日期:{2}\n" +
                            "开盘:{3}\n" +
                            "收盘:{4}\n" +
                            "最高:{5}\n" +
                            "最低:{6}\n" +
                            "手数:{7}\n" +
                            "换手率:{8}%\n" +
                            "成交额:{9}\n" +
                            "20日均线:{10}\n" +
                            "布林上轨:{11}\n" +
                            "布林中轨:{12}\n" +
                            "布林下轨:{13}\n",
                            Base.CurrentIndexCode,
                            comboBox_code.Text,
                            dayData.Date.ToString(),
                            dayData.OpenPrice,
                            dayData.ClosePrice,
                            dayData.HighPrice,
                            dayData.LowPrice,
                            dayData.TotalHand,
                            dayData.HandRate,
                            dayData.TotalAmount,
                            dayIndicator.Ma20.ToString("F2"),
                            dayIndicator.BollUp.ToString("F2"),
                            dayIndicator.BollMd.ToString("F2"),
                            dayIndicator.BollDown.ToString("F2"));
                        textForm.m_Text = text;
                    }
                }
                else
                {
                    textForm.Visible = false;
                }
            }


        }


        private async Task<bool> RunOnceAsync(string code, int n)
        {
            Base.CurrentIndexCode = code;
            await foreach (string str in GetIndexHistory.UpdateDayAsync(code))
            {
                label_Msg.Text = str;
            }
            label_Msg.Text = "";

            indexData = Base.IndexDatabase.GetIndexAsync().Result;

            indicators = null;
            CalcIndicator.CalcAllMaForCode(indexData, out indicators);
            CalcIndicator.CalcBoll(n, indexData, ref indicators);
            return true;
        }
        private async void Button_find_ClickAsync(object sender, EventArgs e)
        {
            if (indexCodeList[comboBox_code.SelectedIndex].Length != 6)
            {
                comboBox_code.BackColor = Color.Red;
                return;
            }
            Clear();
            if (!int.TryParse(textBox_variable.Text, out int n))
            {
                return;
            }
            if (await RunOnceAsync(indexCodeList[comboBox_code.SelectedIndex], n))
            {
                showStartCount = oldShowStartCount = indexData.Count;
                DrawAll(showStartCount);
            }
            else
            {
                label_Msg.Text = "输入错误";
            }

        }
        private void Button_goto_Click(object sender, EventArgs e)
        {

            if (textBox_Date.Text.Length != 8)
            {
                textBox_Date.BackColor = Color.Red;
                textBox_Date.Text = "长度错误";
                return;
            }
            else
            {
                textBox_Date.BackColor = Color.White;
            }
            int.TryParse(textBox_Date.Text, out int date);
            int count = 0;
            foreach (var dayData in indexData)
            {
                if (dayData.Date >= date || count >= indexData.Count - 20)
                {
                    Clear();
                    showStartCount = oldShowStartCount = count;
                    DrawAll(showStartCount);

                    return;
                }
                count++;
            }

            //DateTime date = new DateTime(), textBox1.Text.Take(4), textBox1.Text.Take(4));
        }
        private void Button_Clear_Click(object sender, EventArgs e)
        {
            comboBox_code.SelectedItem = 0;
            Clear();
        }
        private void Button_Strategy_Click(object sender, EventArgs e)
        {
            inFocus = false;
            textForm.Visible = false;
            Form3 form3 = new Form3();
            form3.Show();
        }

        private void button_log_Click(object sender, EventArgs e)
        {
            TextRecord.Record(TestTradBase.record, true);
            TextRecord.OpenRecord();
        }

        private void Form5_FormClosing(object sender, FormClosingEventArgs e)
        {
            textForm.Close();
        }
        private void Form5_Resize(object sender, EventArgs e)
        {
            bmp = new Bitmap(this.Size.Width, this.Size.Height);
            graphics = Graphics.FromImage(bmp);
            GraphicsClear();
        }


    }
}
